/* Copyright (C) 1997-2005, Antony L Hosking.
 * All rights reserved.  */
package Main;

import java.io.*;
import java.util.*;

public class MiniJava {
    static PrintWriter out, dbg;

    static void emitProc(Translate.Frag.Proc f) {
        Translate.Frame frame = f.frame;
        dbg.println("PROCEDURE " + frame.name);
        LinkedList<Translate.Tree.Stm> traced =
            new LinkedList<Translate.Tree.Stm>();
        if (f.body != null) {
            dbg.println("# Before canonicalization (trees):");
            new Translate.Tree.Print(dbg, f.body);
            LinkedList<Translate.Tree.Stm>
		stms = new LinkedList<Translate.Tree.Stm>();
            new Canon.Canon(f.body, stms);
            dbg.println("# After canonicalization (trees):");
            new Translate.Tree.Print(dbg, stms);
            dbg.println("# Tuples:");
            new Canon.Print(dbg, stms);

            dbg.println("# Basic Blocks:");
            Canon.BasicBlocks blocks = new Canon.BasicBlocks(stms);
            for (LinkedList<Translate.Tree.Stm> b : blocks.list)
                new Canon.Print(dbg, b);

            dbg.println("# Trace Scheduled:");
            new Canon.TraceSchedule(blocks, traced);
            new Canon.Print(dbg, traced);
        }
        dbg.println("# With procedure entry/exit:");
        frame.procEntryExit1(traced);
        new Canon.Print(dbg, traced);
        dbg.println("# Instructions:");
        LinkedList<Assem.Instr> insns = new LinkedList<Assem.Instr>();
        Translate.Tree.Visitor<LinkedList<Assem.Instr>, Translate.Temp>
            cg = frame.codegen();
        for (Translate.Tree.Stm s : traced)
            s.accept(cg, insns);
        Translate.Temp.Map map = new Translate.Temp.Map.Default();
        for (Assem.Instr i : insns) {
            dbg.print(i.format(map));
            dbg.print("\t# ");
            for (Translate.Temp d : i.def)
                dbg.print(d + " ");
            dbg.print((i instanceof Assem.Instr.MOVE) ? ":= " : "<- ");
            for (Translate.Temp u : i.use)
                dbg.print(u + " ");
            if (i.jumps.length > 0) {
                dbg.print(": goto ");
                for (Translate.Temp.Label l : i.jumps)
                    dbg.print(l + " ");
            }
            dbg.println();
        }
        dbg.flush();
        frame.procEntryExit2(insns);
        map = new RegAlloc.RegAlloc(frame, insns, dbg);
        dbg.println("# Assembly code:");
        frame.procEntryExit3(insns, map);
        for (Assem.Instr i : insns) {
            String insn = i.format(map);
            out.println(insn);
            dbg.println(insn);
        }
        out.flush();
        dbg.flush();
        dbg.println("END " + frame.name);
        dbg.flush();
    }

    public static boolean nullChecks = true;
    public static boolean useFP = false;
    public static boolean verbose = true;
    public static boolean spilling = true;
    public static boolean coalescing = true;

    private static void usage() {
        String usage =
            "Usage: java Main.MiniJava [-useFP|-nouseFP]"
                + "[-target=[Mips|PPCDarwin|PPCLinux]]" + "<source>.java";
        throw new Error(usage);
    }

    static String mainClass;

    public static void main(String[] argv) throws java.io.IOException {
        Translate.Frame frame = new Mips.Frame();
        String mainClass = null;
        if (argv.length < 1)
            usage();
        if (argv.length > 1)
            for (String arg : argv) {
                if (arg.startsWith("-main="))
                    mainClass = arg.substring(6);
                else if (arg.equals("-target=Mips"))
                    frame = new Mips.Frame();
                else if (arg.equals("-target=PPCDarwin"))
                    frame = new PPC.Frame.Darwin();
                else if (arg.equals("-target=PPCLinux"))
                    frame = new PPC.Frame.Linux();
                else if (arg.startsWith("-"))
                    usage();
            }
        String src = argv[argv.length - 1];
        if (!src.endsWith(".java"))
            usage();
        String dst = src.substring(0, src.lastIndexOf(".java")) + ".s";
        Parse.MiniJava parse =
            new Parse.MiniJava(new java.io.FileInputStream(src));
        Absyn.MiniJava.Unit unit;
        try {
            unit = parse.CompilationUnit();
        } catch (Parse.ParseException e) {
            System.err.println(e.getMessage());
            return;
        } catch (Parse.TokenMgrError e) {
            System.err.println(e.getMessage());
            return;
        }
        Semant.MiniJava semant = new Semant.MiniJava(mainClass);
        Semant.Type types = unit.accept(semant, null);
        if (semant.anyErrors)
            return;
        Translate.MiniJava translate =
            new Translate.MiniJava(unit, types, mainClass, frame);
        out = new PrintWriter(new FileOutputStream(dst));
        dbg =
            (verbose) ? new PrintWriter(System.out)
                : new PrintWriter(new NullOutputStream());
        for (Translate.Frag f : translate.results()) {
            if (f instanceof Translate.Frag.Proc)
                emitProc((Translate.Frag.Proc) f);
            else {
                dbg.println(f);
                dbg.flush();
                out.println(f);
            }
        }
        out.close();
    }
}

class NullOutputStream extends java.io.OutputStream {
    public void write(int b) {}
}
